package cn.silver.module.web.controller;

import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.servlet.JakartaServletUtil;
import cn.silver.framework.core.utils.MessageUtils;
import cn.silver.framework.openapi.constant.ResultEnum;
import cn.silver.framework.openapi.model.Result;
import cn.silver.framework.satoken.model.LoginUser;
import cn.silver.framework.satoken.utils.LoginHelper;
import cn.silver.framework.social.properties.SocialLoginConfigProperties;
import cn.silver.framework.social.properties.SocialProperties;
import cn.silver.framework.social.utils.SocialUtils;
import cn.silver.framework.tenant.helper.TenantHelper;
import cn.silver.framework.web.controller.ApiController;
import cn.silver.module.authority.bean.ClientBean;
import cn.silver.module.authority.service.ISysClientService;
import cn.silver.module.configuration.service.ISysParamService;
import cn.silver.module.system.bean.UserBean;
import cn.silver.module.system.model.RouterModel;
import cn.silver.module.system.model.UserInfoModel;
import cn.silver.module.system.service.ISysMenuService;
import cn.silver.module.system.service.ISysSocialService;
import cn.silver.module.system.service.ISysUserService;
import cn.silver.module.web.model.*;
import cn.silver.module.web.service.IAuthStrategy;
import cn.silver.module.web.service.SysLoginService;
import cn.silver.module.web.service.SysRegisterService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.AuthRequest;
import me.zhyd.oauth.utils.AuthStateUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.net.MalformedURLException;
import java.nio.charset.Charset;
import java.util.List;

/**
 * 认证
 *
 * @author Silver Zhou
 */
@Slf4j
@SaIgnore
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping("/auth")
@Tag(name = "认证授权接口", description = "认证授权接口")
public class AuthController extends ApiController {

    private final ISysUserService userService;
    private final ISysMenuService menuService;
    private final SysLoginService loginService;
    private final ISysClientService clientService;
    private final SysRegisterService registerService;
    private final ISysParamService configService;
    private final SocialProperties socialProperties;
    private final ISysSocialService socialUserService;

    @GetMapping("/valid")
    @Operation(summary = "校验登录信息", description = "用于文件服务器校验登录认证信息，非认证用户不允许访问")
    public Result<Void> validLogin(HttpServletRequest request, HttpServletResponse response) {
        String token = JakartaServletUtil.getHeader(request, "access_token", Charset.defaultCharset());
        if (StringUtils.isBlank(token)) {
            return Result.fail(ResultEnum.UNAUTHORIZED.getCode(), "当前用户未登录或已过期，请登录后访问");
        } else {
            StpUtil.checkLogin();
            return Result.ok();
        }
    }

    /**
     * 获取认证初始化信息
     *
     * @param code 客户端编码
     * @return 认证初始化信息
     */
    @SaIgnore
    @GetMapping("/{code}")
    @Operation(summary = "获取认证初始化信息")
    public Result<AuthModel> init(@PathVariable String code, HttpServletRequest request) throws MalformedURLException {
        AuthModel model = loginService.getAuthModel(code, request);
        return Result.ok(model);
    }

    /**
     * 登录方法
     *
     * @param loginModel 登录信息
     * @return 结果
     */
    @PostMapping("/login")
    @Operation(summary = "认证登录")
    public Result<LoginResultModel> login(@Validated @RequestBody LoginModel loginModel) {
        // 授权类型和客户端id
        String clientId = loginModel.getClientId();
        String grantType = loginModel.getGrantType();
        ClientBean client = clientService.selectById(clientId);
        // 查询不到 client 或 client 内不包含 grantType
        if (ObjectUtil.isNull(client) || !client.getGrantTypes().contains(grantType)) {
            log.info("客户端id: {} 认证类型：{} 异常!.", clientId, grantType);
            return Result.fail(ResultEnum.DATA_VALIDATED_FAILED.getCode(), MessageUtils.message("auth.grant.error"));
        }
        // 校验租户
        loginService.checkTenant(loginModel.getTenantId());
        // 登录
        return Result.ok(IAuthStrategy.login(loginModel, client));
    }

    /**
     * 获取用户信息
     *
     * @return 用户信息
     */
    @SaCheckLogin
    @GetMapping("/getInfo")
    @Operation(summary = "获取登录用户基础信息")
    public Result<UserInfoModel> getInfo() {
        UserInfoModel userInfoModel = new UserInfoModel();
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (TenantHelper.isEnable() && LoginHelper.isSuperAdmin()) {
            // 超级管理员 如果重新加载用户信息需清除动态租户
            TenantHelper.clearDynamic();
        }
        UserBean user = userService.selectById(loginUser.getId());
        if (ObjectUtil.isNull(user)) {
            return Result.fail(ResultEnum.UNAUTHORIZED.getCode(), "没有权限访问用户数据!");
        }
        userInfoModel.setUser(user);
        userInfoModel.setRoles(loginUser.getRoleKeys());
        userInfoModel.setPermissions(loginUser.getPermission());
        return Result.ok(userInfoModel);
    }

    /**
     * 获取路由信息
     *
     * @return 路由信息
     */
    @GetMapping("/getRouters")
    @Operation(summary = "获取用户访问列表")
    public Result<List<RouterModel>> getRouters() {
        return Result.ok(menuService.selectLocalRouter());
    }

    /**
     * 第三方登录请求
     *
     * @param source 登录来源
     * @return 结果
     */
    @GetMapping("/binding/{source}")
    @Operation(summary = "绑定第三方平台账号")
    public Result<String> authBinding(@PathVariable("source") String source) {
        SocialLoginConfigProperties obj = socialProperties.getType().get(source);
        if (ObjectUtil.isNull(obj)) {
            return Result.fail(ResultEnum.CONFLICT.getCode(), source + "平台账号暂不支持");
        }
        AuthRequest authRequest = SocialUtils.getAuthRequest(source, socialProperties);
        String authorizeUrl = authRequest.authorize(AuthStateUtils.createState());
        return Result.ok("操作成功", authorizeUrl);
    }

    /**
     * 第三方登录回调业务处理 绑定授权
     *
     * @param loginModel 请求体
     * @return 结果
     */
    @PostMapping("/social/callback")
    @Operation(summary = "第三方授权登录请求")
    public Result<Void> socialCallback(@RequestBody LoginSocialModel loginModel) {
        // 获取第三方登录信息
        AuthResponse<AuthUser> response = SocialUtils.loginAuth(loginModel.convertSocialModel(), socialProperties);
        AuthUser authUserData = response.getData();
        // 判断授权响应是否成功
        if (!response.ok()) {
            return Result.fail(ResultEnum.CONFLICT.getCode(), response.getMsg());
        }
        loginService.socialRegister(authUserData);
        return Result.ok();
    }


    /**
     * 取消授权
     *
     * @param socialId socialId
     */
    @Operation(summary = "取消第三方登录授权信息")
    @DeleteMapping(value = "/unlock/{socialId}")
    public Result<Void> unlockSocial(@PathVariable String socialId) {
        socialUserService.delete(socialId);
        return Result.ok();
    }


    /**
     * 退出登录
     */
    @PostMapping("/logout")
    @Operation(summary = "用户退出登录")
    public Result<Void> logout() {
        loginService.logout();
        return Result.ok("退出成功");
    }

    /**
     * 用户注册
     */
    @PostMapping("/register")
    @Operation(summary = "提交用户注册请求")
    public Result<Void> register(@Validated @RequestBody RegisterModel user) {
        ClientBean bean = this.clientService.selectById(user.getClientId());
        if (!bean.getRegister()) {
            return Result.fail(ResultEnum.CONFLICT.getCode(), "当前客户端没有开启注册功能！");
        }
        registerService.register(user);
        return Result.ok();
    }

    /**
     * 登录页面租户下拉框
     *
     * @return 租户列表
     */
//	@GetMapping("/tenant/list")
//	public Result<AuthTenantModel> tenantList(HttpServletRequest request) throws Exception {
//		List<SysTenantModel> tenantList = tenantService.selectList(new SysTenant());
//		// 获取域名
//		String host;
//		String referer = request.getHeader("referer");
//		if (StringUtils.isNotBlank(referer)) {
//			// 这里从referer中取值是为了本地使用hosts添加虚拟域名，方便本地环境调试
//			host = referer.split("//")[1].split("/")[0];
//		} else {
//			host = new URL(request.getRequestURL().toString()).getHost();
//		}
//		// 根据域名进行筛选
//		List<SysTenantModel> list = StreamUtils.filter(tenantList, vo ->
//				StringUtils.equals(vo.getDomain(), host));
//		// 返回对象
//		AuthTenantModel vo = new AuthTenantModel();
//		vo.setDicts(CollUtil.isNotEmpty(list) ? list : tenantList);
//		vo.setEnabled(TenantHelper.isEnable());
//		return Result.ok(vo);
//	}

}
